home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
THINKC
/
3_0
/
RAMSTART
/
RS(COPY).C
< prev
next >
Wrap
Text File
|
1988-01-13
|
18KB
|
765 lines
/*
RS(Copy).c
P/O RamStart.c
*/
#include <MemoryMgr.h>
#include <ResourceMgr.h>
#include <HFS.h>
#include <OSUtil.h>
#include <SegmentLdr.h>
#include <setjmp.h>
#include "RS.h"
extern jmp_buf env;
/* Defined here */
/*-- length of a file name */
#define NameMax 64
typedef struct { /* Enough data about each file to recreate it. */
short refNum, rRefNum;
long lgLen, rLgLen;
char fndrInfo[16];
long crDat, modDat;
char dontClose, rDontClose; /* It is a bad thing to close us or the System. */
char name[NameMax];
} FileList;
#define HFS_System (FSFCBLen >= 0) /* Bill */
#define mfsSigWord 0xd2d7
#define hfsSigWord 0x4244
char CopyFolder();
static ioParam newIO; /* for closing the file from NoRamDisk() */
/* // */
/* Called if there is a control to file, to copy the files listed in it to
the RAM disk. Notice if a system or a finder were copied. Work in the
default volume. Several special names are recognized: "=<appl name>" to
substitute for the Finder on exit, "+─" to copy the files in the same
folder as the control file, and empty or blank lines and lines starting with
an asterisk, "*", which are ignored. */
CopyCtrlFile( ctrlFileName, ramDrvNum, exitApplP )
char *ctrlFileName;
short ramDrvNum;
char **exitApplP;
{
short mssg;
jmp_buf oldEnv;
fileParam fpb1;
ioParam pb;
FileList *fileList, *flp;
short nFiles, /* number of fileList entries used */
avail, opened; /* number of FCB slots available and used */
char *exitAppl;
short i, result;
char fName[MAXLINE+1];
char hadX = 0;
char hadCopyFolder = FALSE;
char pathBuf[522];
TestDLOG();
/* Create the file list on the heap, 'cause it takes 4.8K. */
exitAppl = NewPtr( NameMax ); /* In case we get an exit appl */
exitAppl[0] = 0;
if( (avail = FCBSlots() - 5) < 4 )
error("too few fcbs, avail=^2", (long)avail);
fileList = (FileList *)NewPtr( (avail+2) * sizeof(FileList) );
/* If TestDLOG() finds that something has happened, we need to clean up
by closing the files in fileList and removing fileList. */
nFiles = opened = 0; /* initialize in case of early withdrawal */
newIO.ioRefNum = 0;
BlockMove( env, oldEnv, sizeof(jmp_buf) );
if( (mssg = setjmp( env )) ) {
PBClose( &pb, FALSE );
CloseFiles( fileList, nFiles );
DisposPtr( fileList );
DisposPtr( exitAppl );
BlockMove( oldEnv, env, sizeof(jmp_buf) );
longjmp( env, mssg );
}
/* Open the control file data fork. */
Clear( pb );
pb.ioNamePtr = (StringPtr)ctrlFileName;
pb.ioMisc = pathBuf;
if( PBOpen(&pb, FALSE) ) {
error("\pcan't open control file '^1', ioResult=^2", (long)pb.ioResult, (long)0, ctrlFileName);
BlockMove( oldEnv, env, sizeof(jmp_buf) );
return( 0 );
}
/* // */
while( TRUE ) {
TestDLOG();
pb.ioBuffer = &fName[1];
pb.ioReqCount = MAXLINE;
pb.ioPosMode = ('\r' << 8) | 0x80; /* read lines at mark */
if( PBRead(&pb, FALSE) ) {
if( pb.ioResult != eofErr )
error("\pcan't read control file '^1', ioResult=^2", (long)pb.ioResult, (long)0, ctrlFileName);
else if( pb.ioActCount == 0 ) /* end of file */
hadX |= CopyList( fileList, nFiles, ramDrvNum, exitAppl );
break;
}
fName[0] = pb.ioActCount; /* length of line */
if( fName[pb.ioActCount] == '\r' )
--fName[0];
/* // */
if( ! fName[0] || fName[1] == ' ' || fName[1] == '*' )
continue; /* blank line */
else if( fName[1] == '=' ) {
if( fName[0] > NameMax ) /* set exit appl */
fName[0] = NameMax;
BlockMove( &fName[2], &exitAppl[1], (exitAppl[0] = fName[0] - 1) );
}
else if( EqualString(fName, "\p+─", FALSE, TRUE) )
hadCopyFolder = TRUE; /* will copy our folder */
else { /* a file name */
Clear( fpb1 );
fpb1.ioNamePtr = (StringPtr)fName;
while( PBGetFInfo(&fpb1, FALSE) ) { /* catch bad names here */
ParamText( fName, ctrlFileName, NULL, NULL );
if( Alert(alrtBadName, FALSE) == 1 )
break;
TestDLOG(); /* maybe the user pushed a disk in? */
}
if( !fpb1.ioResult ) {
opened += myOpenFile( fName, &fpb1, &fileList[nFiles++], &result );
if( result ) /* anything we can _GetFileInfo on should be openable. */
error("\pcan't open file, result=^2", (long)result);
if( opened >= avail ) {
hadX |= CopyList( fileList, nFiles, ramDrvNum, exitAppl );
nFiles = opened = 0;
}
}
}
}
PBClose( &pb, FALSE );
DisposPtr( fileList );
if( exitAppl[0] )
*exitApplP = exitAppl;
else DisposPtr( exitAppl );
BlockMove( oldEnv, env, sizeof(jmp_buf) );
if( hadCopyFolder )
hadX |= CopyFolder( ramDrvNum, ctrlFileName, *exitApplP );
return( hadX );
}
/* // */
/* Copy the files in the same folder as this program to the RAM disk.
Don't copy this program or the desktop file. Notice if a system or a
finder were copied; bit-code the result. Work in the default volume.
Under HFS, we don't have to worry about folders -- in fact, the folder in
the Finder info isn't even set! Simply copy all the files in the current
"volume" (working directory) to the RAM disk. */
char CopyFolder( ramDrvNum, ourName, exitAppl )
short ramDrvNum; /* --> */
char *ourName; /* --> */
char *exitAppl; /* --> */
{
short mssg;
jmp_buf oldEnv;
fileParam fpb;
HVolumeParam vpb;
short ourFolder;
short nFiles, avail, opened;
FileList *fileList, *flp;
short i, result;
char fName[MAXLINE];
long hadX = 0;
char isHFS;
TestDLOG();
/* Create the file list on the heap, 'cause it takes 4.8K. */
if( (avail = FCBSlots() - 5) < 4 )
error("too few fcbs, avail=^2", (long)avail);
fileList = (FileList *)NewPtr( (avail+2) * sizeof(FileList) );
/* If TestDLOG() finds that something has happened, we need to clean up
by closing the files in fileList and removing fileList. */
nFiles = opened = 0;
BlockMove( env, oldEnv, sizeof(jmp_buf) );
if( (mssg = setjmp( env )) ) {
CloseFiles( fileList, nFiles );
DisposPtr( fileList );
BlockMove( oldEnv, env, sizeof(jmp_buf) );
longjmp( env, mssg );
}
TestDLOG();
/* Find our folder. */
Clear( vpb );
vpb.ioTrap = -1; /* hideous and dumb bug in System 3.1 HFS */
PBHGetVInfo( &vpb, FALSE );
if( (isHFS = (HFS_System && vpb.ioVSigWord == hfsSigWord)) )
ourFolder = 0;
else {
Clear( fpb );
fpb.ioNamePtr = (StringPtr)ourName; /* Our name better be 31 chars or less, or it will... */
if( PBGetFInfo( &fpb, FALSE ) ) /* ...have been truncated here. */
error( "\pcan't get our file info" );
ourFolder = fpb.ioFlFndrInfo.fdFldr;
}
/* // */
/* Open several files at a time and then copy them. This speeds up
copying of large numbers of files by reducing the number of times
the directory blocks must be seeked to (except under HFS, which
can be woefully inefficient). */
Clear( fpb );
fpb.ioFDirIndex = 1;
fpb.ioNamePtr = (StringPtr)fName;
while( !fpb.ioResult ) {
/* Open input files and place them in the list to copy if in our folder
and not us, until we can't open any more files. */
for( nFiles = opened = 0; opened < avail; ++fpb.ioFDirIndex ) {
TestDLOG();
if( PBGetFInfo(&fpb, FALSE) ) {
if( fpb.ioResult != fnfErr )
error("\pcan't get file info for folder test for '^1', ioResult=^2", (long)fpb.ioResult, (long)0, fName);
break;
}
if( fName[0] >= NameMax )
error("\pfile name '^1' too long (>^2)", (long)NameMax, (long)0, fName); /* shouldn't happen */
if( (isHFS || ourFolder == fpb.ioFlFndrInfo.fdFldr)
&& ! EqualString( CurApName, fName, FALSE, TRUE )
&& ! EqualString( ourName, fName, FALSE, TRUE )
&& ! EqualString( "\pDeskTop", fName, FALSE, TRUE ) )
{
opened += myOpenFile( fName, &fpb, &fileList[nFiles++], &result );
if( result )
error("\pCopyFolder() can't open file, result=^2", (long)result);
}
}
hadX |= CopyList( fileList, nFiles, ramDrvNum, exitAppl );
}
DisposPtr( fileList );
BlockMove( oldEnv, env, sizeof(jmp_buf) );
return( hadX );
}
/* // */
/* Open a file, both data and resource forks, and save the data needed to
recreate the file. If a fork was opened, its refNum will be non-zero.
Return non-zero ioResult if a file can't be opened. */
short myOpenFile( fName, fpbp, flp, resultp )
char *fName;
fileParam *fpbp;
FileList *flp;
short *resultp;
{
ioParam io;
short opened = 0;
SimpleFName( fName, flp->name );
ShowFileName( flp->name, ctlIOpenMsg );
/* Set up defaults in file list entry. */
flp->refNum = flp->rRefNum = 0; /* not open */
flp->lgLen = fpbp->ioFlLgLen;
flp->rLgLen = fpbp->ioFlRLgLen;
BlockMove( &fpbp->ioFlFndrInfo, flp->fndrInfo, 16);
flp->crDat = fpbp->ioFlCrDat;
flp->modDat = fpbp->ioFlMdDat;
flp->dontClose = flp->rDontClose = FALSE;
/* Set up open pb. */
Clear( io );
io.ioNamePtr = (StringPtr)fName;
/* // */
/* Open the data fork if there is one and it's not the System file --
no, do copy the System file data fork; people complained mightily
that they couldn't copy the System from the RAM disk. Lets see how
they like losing space, instead! */
if( fpbp->ioFlLgLen /* && !EqualString(SysResName, fName, FALSE, TRUE) */ ) {
if( PBOpen(&io, FALSE) ) {
switch( io.ioResult )
{
case opWrErr:
flp->dontClose = TRUE;
break;
default:
*resultp = io.ioResult;
return( 0 );
}
}
flp->refNum = io.ioRefNum;
++opened;
}
TestDLOG();
/* Open the resource fork if there is one. */
if( fpbp->ioFlRLgLen ) {
if( PBOpenRF(&io, FALSE) ) {
switch( io.ioResult ) {
case opWrErr:
flp->rDontClose = TRUE;
break;
default:
if( (io.ioRefNum = flp->refNum) )
PBClose( &io, FALSE );
*resultp = io.ioResult;
return( 0 );
}
}
flp->rRefNum = io.ioRefNum;
++opened;
}
*resultp = 0;
return( opened );
}
/* // */
/* Copy the open files in the list. */
CopyList( fileList, nFiles, ramDrvNum, exitAppl )
FileList *fileList;
short nFiles;
short ramDrvNum;
char *exitAppl;
{
short i;
long hadX = 0;
register FileList *flp;
/* Copy the files in the list to the RAM disk. */
for( i = nFiles, flp = fileList; i; --i, ++flp ) {
ShowFileName( flp->name, ctlICopyMsg );
if( CopyFile( flp, ramDrvNum ) ) { /* File may not fit. */
if( EqualString(exitAppl, flp->name, FALSE, TRUE) )
hadX |= HadFinder;
if( EqualString(SysResName, flp->name, FALSE, TRUE) ) {
hadX |= HadSystem;
}
}
}
CloseFiles( fileList, nFiles ); /* done with them */
return( hadX );
}
/* // */
/* Copy a file, both data and resource forks. Make sure the file fits.
The copy has the same Type and Creator as the original, but its folder is 0
and it is not init'ed. Work in the default volume and the RAM disk. */
CopyFile( flp, ramDrvNum )
FileList *flp; /* --> */
short ramDrvNum; /* --> */
{
fileParam newF;
ioParam oldIO;
Ptr iop;
char dontClose;
char fits = TRUE;
TestDLOG();
/* Make pb for SetFileInfo. */
Clear( newF );
newF.ioNamePtr = (StringPtr)flp->name;
newF.ioVRefNum = ramDrvNum;
BlockMove( flp->fndrInfo, &newF.ioFlFndrInfo, 16 );
newF.ioFlCrDat = flp->crDat;
newF.ioFlMdDat = flp->modDat;
/* Make io pb's for old and new files. */
Clear( oldIO );
Clear( newIO );
newIO.ioNamePtr = (StringPtr)flp->name;
newIO.ioVRefNum = ramDrvNum;
/* Create the new file. */
fits = TRUE;
if( PBCreate( &newIO, FALSE ) ) {
if( newIO.ioResult == dirFulErr )
;
else if( newIO.ioResult == dupFNErr ) {
if( Alert(alrtAlreadyCopied, FALSE) == alreadyCopiedCancel )
longjmp( env, 'SZ' ); /* Never returns. */
return( FALSE ); /* avoid second alert */
}
else error("\pcan't create new file, ioResult=^2", (long)newIO.ioResult);
fits = FALSE;
}
TestDLOG();
/* // */
/* Copy the data fork if there is one. */
if( fits && (oldIO.ioRefNum = flp->refNum) ) {
if( PBOpen( &newIO, FALSE ) )
error("\pcan't open new file");
newIO.ioMisc = (Ptr)flp->lgLen; /* Copy in one extent. */
if( (fits = ! PBSetEOF( &newIO, FALSE )) )
CopyFork( &oldIO, &newIO );
PBClose( &newIO, FALSE );
newIO.ioRefNum = 0;
}
TestDLOG();
/* Copy the resource fork. */
if( fits && (oldIO.ioRefNum = flp->rRefNum) ) {
oldIO.ioMisc = newIO.ioMisc = 0;
if( PBOpenRF( &newIO, FALSE ) )
error("\pcan't open new resource file");
newIO.ioMisc = (Ptr)flp->rLgLen; /* Copy in one extent. */
if( (fits = ! PBSetEOF( &newIO, FALSE )) )
CopyFork( &oldIO, &newIO );
PBClose( &newIO, FALSE );
newIO.ioRefNum = 0;
}
/* // */
if( !fits ) {
newIO.ioRefNum = 0;
PBDelete( &newF, FALSE );
if( Alert(alrtDidntFit, NULL) == didntfitICancel ) /* File name placed in ^0 by ShowFileName(). */
longjmp( env, 'SZ' ); /* Never returns. */
}
else {
newF.ioFlFndrInfo.fdFlags &= ~0x0100; /* Not "inited". Doesn't agree with IM. */
newF.ioFlFndrInfo.fdLocation.v = newF.ioFlFndrInfo.fdLocation.h = 0;
/* Put system files in "Empty folder". This didn't work with the v2.6
Finder, but it works again with later versions. */
{
short i;
static long types[] = { 'MACS', 'IWRX', 'IWRT', 'LWRT',
'macs', 'acss', 'sysc', 'KEYC',
'keyb', 'cdsc', 'mous', 'soun',
'boot', 0L };
newF.ioFlFndrInfo.fdFldr = 0;
for( i = 0; types[i]; ++i ) {
if( newF.ioFlFndrInfo.fdCreator == types[i] )
newF.ioFlFndrInfo.fdFldr = -1;
}
}
if( EqualString(SysResName, flp->name, FALSE, TRUE) )
CopyBootBlocks( ramDrvNum );
PBSetFInfo( &newF, FALSE );
}
return( fits );
}
/* // */
/* Copy a fork of a file. */
CopyFork( old, new )
ioParam *old, *new; /* --> Changes not used by caller. */
{
Ptr buf;
long len; /* length of buf */
short mssg;
jmp_buf oldEnv;
TestDLOG();
len = (long)new->ioMisc; /* length of this fork */
if( len == 0 )
return( TRUE );
if( len > 10*1024 ) /* Make a reasonable size buffer, to limit the time... */
len = 10*1024; /* ...we don't get events. */
if( !(buf = NewPtr(len)) ) { /* Get a buffer. */
len = 512; /* Try for a small buffer. */
if( !(buf = NewPtr(len)) )
error("\pcan't get small buffer");
return;
}
/* If TestDLOG() finds something has happened, dispose the buffer. */
BlockMove( env, oldEnv, sizeof(jmp_buf) );
if( (mssg = setjmp( env )) ) {
DisposPtr( buf );
BlockMove( oldEnv, env, sizeof(jmp_buf) );
longjmp( env, mssg );
}
old->ioReqCount = len;
old->ioBuffer = new->ioBuffer = buf;
old->ioPosOffset = new->ioPosOffset = 0;
old->ioPosMode = new->ioPosMode = 1; /* I/O at ioPosOffset. */
old->ioResult = new->ioResult = 0;
while( ! (old->ioResult | new->ioResult) ) {
TestDLOG();
if( PBRead(old, FALSE) == noErr /* Stop at error... */
|| old->ioResult == eofErr ) /* ...but copy last block. */
{
TestDLOG();
new->ioReqCount = old->ioActCount;
PBWrite( new, FALSE );
}
}
DisposPtr( buf );
BlockMove( oldEnv, env, sizeof(jmp_buf) );
if( old->ioResult != eofErr || new->ioResult != noErr )
error("\ptrouble ^2 ^3 in CopyFork", (long)old->ioResult, (long)new->ioResult);
}
/* // */
/* Close the files in fileList that should be closed. */
CloseFiles( flp, nFiles )
register FileList *flp;
register short nFiles;
{
ioParam io;
if( newIO.ioRefNum ) /* close file we were copying */
PBClose( &newIO, FALSE );
Clear( io );
for( ; nFiles; --nFiles, ++flp ) {
if( (io.ioRefNum = flp->refNum) && !flp->dontClose ) {
PBClose( &io, FALSE );
flp->refNum = 0;
}
if( (io.ioRefNum = flp->rRefNum) && !flp->rDontClose ) {
PBClose( &io, FALSE );
flp->rRefNum = 0;
}
}
}
/* // */
/* Count the number of available FCB slots. We will open about that many
files (forks), leaving a few for slack and the file to copy with. */
short FCBSlots()
{
register short i, fcbLen, avail = 0;
fcbLen = (HFS_System) ? FSFCBLen : 30;
for( i = 2; i < *(short *)FCBSPtr; i += fcbLen )
if( !*(long *)&FCBSPtr[i] )
++avail;
return( avail );
}
/* // */
/* Copy the boot blocks to the RAM disk. Since Apple refuses to tell us
what the boot blocks contain or whether they may be directly copied, we'll
just wing it and hope for the best. */
CopyBootBlocks( ramDrvNum )
short ramDrvNum;
{
ioParam pb;
char buf[1024];
Clear( pb );
pb.ioVRefNum = OurDriveNum();
pb.ioRefNum = GetDriverNum( pb.ioVRefNum );
pb.ioBuffer = buf;
pb.ioReqCount = 1024;
pb.ioPosMode = fsFromStart;
pb.ioPosOffset = 0;
if( PBRead(&pb, FALSE) || pb.ioActCount != pb.ioReqCount ) {
error("\pcan't read boot blocks, ioResult=^2", (long)pb.ioResult);
return;
}
pb.ioVRefNum = ramDrvNum;
pb.ioRefNum = GetDriverNum( pb.ioVRefNum );
pb.ioPosOffset = 0;
if( PBWrite(&pb, FALSE) || pb.ioActCount != pb.ioReqCount )
error("\pcan't write boot blocks, ioResult=^2", (long)pb.ioResult);
}
/* // */
/* Parse off a simple file name from a path name, a pascal string. Copy the
result to simple, a pascal string. */
SimpleFName( path, simple )
char *path, *simple;
{
short i;
char *cP;
for( i = path[0], cP = &path[i]; i > 0 && *cP != ':'; --i, --cP )
;
simple[0] = path[0] - i;
BlockMove( &cP[1], &simple[1], simple[0] );
}
short
OurDriveNum()
{
WDPBRec pb;
QElem *vcbp;
short ourDrvNum;
Clear( pb );
PBHGetVol( &pb, FALSE ); /* Are we on a Sony drive? */
if( (HFS_System) )
pb.ioVRefNum = pb.ioWDVRefNum; /* Replace WD with real volume #. */
vcbp = VCBQHdr.qHead;
while( TRUE ) { /* Convert volume RefNum to a drive number. */
if( *(short *)&vcbp->qData[78-6] == pb.ioVRefNum ) {
ourDrvNum = *(short *)&vcbp->qData[72-6];
break;
}
if( ! (vcbp = vcbp->qLink) ) {
error("\pcan't find our drive #");
ourDrvNum = -1;
}
}
return( ourDrvNum );
}
short
GetDriverNum( driveNum )
short driveNum;
{
DrvQElPtr dqp;
for( dqp = (DrvQElPtr)DrvQHdr.qHead; dqp; dqp = (DrvQElPtr)dqp->qLink ) {
if( dqp->dQDrive == driveNum )
return( dqp->dQRefNum );
}
return( 0 );
}